package com.budwk.app.miniapp.services.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.exception.ServiceException;
import com.budwk.app.miniapp.common.CacheConstants;
import com.budwk.app.miniapp.models.WxVolunteer;
import com.budwk.app.miniapp.models.WxVolunteerSMPassCheck;
import com.budwk.app.miniapp.models.vo.WxEventStatisticVO;
import com.budwk.app.miniapp.models.vo.WxEventVo;
import com.budwk.app.miniapp.services.WxeventscheduleService;
import com.budwk.app.miniapp.services.WxvolunteerService;
import com.budwk.app.miniapp.utils.DistanceUtils;
import com.budwk.app.miniapp.utils.RedisUtils;
import com.budwk.app.miniapp.utils.WechatMiniProgramTemplateMessageUtil;
import com.budwk.starter.common.exception.BaseException;
import com.budwk.starter.common.page.PageUtil;
import com.budwk.starter.common.page.Pagination;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.budwk.app.miniapp.models.WxEvent;
import com.budwk.app.miniapp.services.WxeventService;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.redisson.api.RedissonClient;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@IocBean(args = {"refer:dao"})
public class WxeventServiceImpl extends BaseServiceImpl<WxEvent> implements WxeventService {
    public WxeventServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private WxeventscheduleService wxeventscheduleService;

    @Inject
    private WxvolunteerService wxvolunteerService;

    @Inject
    private RedisService redisService;

    @Inject
    private RedissonClient redissonClient;


    /**
     * 构造查询SQL语句
     */
    @Override
    public Cnd querySqlBuild(WxEvent bean, String pageOrderName, String pageOrderBy) {
        Cnd cnd = Cnd.NEW();
        if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
            cnd.orderBy(pageOrderName + ",create_time", PageUtil.getOrder(pageOrderBy));
        } else {
            cnd.orderBy("create_time", PageUtil.getOrder("desc"));
        }
        if (bean.getId() != null && Strings.isNotBlank(bean.getId().toString())) {
            cnd.and("id", "=", bean.getId());
        }
        if (bean.getOpenid() != null && Strings.isNotBlank(bean.getOpenid().toString())) {
            cnd.and("openid", "=", bean.getOpenid());
        }
        if (bean.getUserName() != null && Strings.isNotBlank(bean.getUserName().toString())) {
            cnd.and("user_name", "=", bean.getUserName());
        }
        if (bean.getEventType() != null && Strings.isNotBlank(bean.getEventType().toString())) {
            cnd.and("event_type", "=", bean.getEventType());
        }
        if (bean.getEventContent() != null && Strings.isNotBlank(bean.getEventContent().toString())) {
            cnd.and("event_content", "=", bean.getEventContent());
        }
        if (bean.getEventPicUrl() != null && Strings.isNotBlank(bean.getEventPicUrl().toString())) {
            cnd.and("event_pic_url", "=", bean.getEventPicUrl());
        }
        if (bean.getEventCreateTime() != null && Strings.isNotBlank(bean.getEventCreateTime().toString())) {
            cnd.and("event_create_time", "=", bean.getEventCreateTime());
        }
        if (bean.getEventCompleteTime() != null && Strings.isNotBlank(bean.getEventCompleteTime().toString())) {
            cnd.and("event_complete_time", "=", bean.getEventCompleteTime());
        }
        if (bean.getEventAddress() != null && Strings.isNotBlank(bean.getEventAddress().toString())) {
            cnd.and("event_address", "=", bean.getEventAddress());
        }
        if (bean.getEventReminder() != null && Strings.isNotBlank(bean.getEventReminder().toString())) {
            cnd.and("event_reminder", "=", bean.getEventReminder());
        }
        if (bean.getEventPriority() != null && Strings.isNotBlank(bean.getEventPriority().toString())) {
            cnd.and("event_priority", "=", bean.getEventPriority());
        }
        if (bean.getEventPhone() != null && Strings.isNotBlank(bean.getEventPhone().toString())) {
            cnd.and("event_phone", "=", bean.getEventPhone());
        }
        if (bean.getEventLabel() != null && Strings.isNotBlank(bean.getEventLabel().toString())) {
            cnd.and("event_label", "=", bean.getEventLabel());
        }
        if (bean.getEventContentType() != null && Strings.isNotBlank(bean.getEventContentType().toString())) {
            cnd.and("event_content_type", "=", bean.getEventContentType());
        }
        if (bean.getEventReminderStatus() != null && Strings.isNotBlank(bean.getEventReminderStatus().toString())) {
            cnd.and("event_reminder_status", "=", bean.getEventReminderStatus());
        }
        if (bean.getEventSysStatus() != null && Strings.isNotBlank(bean.getEventSysStatus().toString())) {
            cnd.and("event_sys_status", "=", bean.getEventSysStatus());
        }
        if (bean.getEventIndex() != null && Strings.isNotBlank(bean.getEventIndex().toString())) {
            cnd.and("event_index", "=", bean.getEventIndex());
        }
        if (bean.getEventVideo() != null && Strings.isNotBlank(bean.getEventVideo().toString())) {
            cnd.and("event_vide", "=", bean.getEventVideo());
        }
        if (bean.getEventFollowers() != null && Strings.isNotBlank(bean.getEventFollowers().toString())) {
            cnd.and("event_followers", "=", bean.getEventFollowers());
        }
        if (bean.getEventProperties() != null && Strings.isNotBlank(bean.getEventProperties().toString())) {
            cnd.and("event_properties", "=", bean.getEventProperties());
        }
        if (bean.getEventNature() != null && Strings.isNotBlank(bean.getEventNature().toString())) {
            cnd.and("event_nature", "=", bean.getEventNature());
        }
        if (bean.getEventRole() != null && Strings.isNotBlank(bean.getEventRole().toString())) {
            cnd.and("event_role", "=", bean.getEventRole());
        }
        if (bean.getEventTop() != null && Strings.isNotBlank(bean.getEventTop().toString())) {
            cnd.and("event_top", "=", bean.getEventTop());
        }
        if (bean.getEventProvince() != null && Strings.isNotBlank(bean.getEventProvince().toString())) {
            cnd.and("event_province", "=", bean.getEventProvince());
        }
        if (bean.getEventCity() != null && Strings.isNotBlank(bean.getEventCity().toString())) {
            cnd.and("event_city", "=", bean.getEventCity());
        }
        if (bean.getEventDistrict() != null && Strings.isNotBlank(bean.getEventDistrict().toString())) {
            cnd.and("event_district", "=", bean.getEventDistrict());
        }
        if (bean.getEventStreet() != null && Strings.isNotBlank(bean.getEventStreet().toString())) {
            cnd.and("event_street", "=", bean.getEventStreet());
        }
        if (bean.getEventAdcode() != null && Strings.isNotBlank(bean.getEventAdcode().toString())) {
            cnd.and("event_adcode", "=", bean.getEventAdcode());
        }
        if (bean.getEventAreaType() != null && Strings.isNotBlank(bean.getEventAreaType().toString())) {
            cnd.and("event_area_type", "=", bean.getEventAreaType());
        }
        if (bean.getCompleteType() != null && Strings.isNotBlank(bean.getCompleteType().toString())) {
            cnd.and("complete_type", "=", bean.getCompleteType());
        }
        if (bean.getVolunteerName() != null && Strings.isNotBlank(bean.getVolunteerName().toString())) {
            cnd.and("volunteer_name", "=", bean.getVolunteerName());
        }
        if (bean.getVolunteerSex() != null && Strings.isNotBlank(bean.getVolunteerSex().toString())) {
            cnd.and("volunteer_sex", "=", bean.getVolunteerSex());
        }
        if (bean.getVolunteerPhone() != null && Strings.isNotBlank(bean.getVolunteerPhone().toString())) {
            cnd.and("volunteer_phone", "=", bean.getVolunteerPhone());
        }
        if (bean.getVolunteerYear() != null && Strings.isNotBlank(bean.getVolunteerYear().toString())) {
            cnd.and("volunteer_year", "=", bean.getVolunteerYear());
        }
        if (bean.getVolunteerCompleteNum() != null && Strings.isNotBlank(bean.getVolunteerCompleteNum().toString())) {
            cnd.and("volunteer_complete_num", "=", bean.getVolunteerCompleteNum());
        }
        if (bean.getMsgauditPassTime() != null && Strings.isNotBlank(bean.getMsgauditPassTime().toString())) {
            cnd.and("msgaudit_passTime", "=", bean.getMsgauditPassTime());
        }
        if (bean.getVolunteerOrdertime() != null && Strings.isNotBlank(bean.getVolunteerOrdertime().toString())) {
            cnd.and("volunteer_ordertime", "=", bean.getVolunteerOrdertime());
        }
        if (bean.getVolunteerWhetherHelp() != null && Strings.isNotBlank(bean.getVolunteerWhetherHelp().toString())) {
            cnd.and("volunteer_whether_help", "=", bean.getVolunteerWhetherHelp());
        }
        if (bean.getSpecialRequirement() != null && Strings.isNotBlank(bean.getSpecialRequirement().toString())) {
            cnd.and("special_requirement", "=", bean.getSpecialRequirement());
        }
        if (bean.getCreateBy() != null && Strings.isNotBlank(bean.getCreateBy().toString())) {
            cnd.and("create_by", "=", bean.getCreateBy());
        }
        if (bean.getCreateTime() != null && Strings.isNotBlank(bean.getCreateTime().toString())) {
            cnd.and("create_time", "=", bean.getCreateTime());
        }
        if (bean.getUpdateBy() != null && Strings.isNotBlank(bean.getUpdateBy().toString())) {
            cnd.and("update_by", "=", bean.getUpdateBy());
        }
        if (bean.getUpdateTime() != null && Strings.isNotBlank(bean.getUpdateTime().toString())) {
            cnd.and("update_time", "=", bean.getUpdateTime());
        }
        if (bean.getDelFlag() != null && Strings.isNotBlank(bean.getDelFlag().toString())) {
            cnd.and("del_flag", "=", bean.getDelFlag());
        }
        if (bean.getEventNickname() != null && Strings.isNotBlank(bean.getEventNickname().toString())) {
            cnd.and("event_nickname", "=", bean.getEventNickname());
        }
        if (bean.getEventSex() != null && Strings.isNotBlank(bean.getEventSex().toString())) {
            cnd.and("event_sex", "=", bean.getEventSex());
        }
        if (bean.getVolunteerId() != null && Strings.isNotBlank(bean.getVolunteerId().toString())) {
            cnd.and("volunteer_id", "=", bean.getVolunteerId());
        }
        if (bean.getAuditingType() != null && Strings.isNotBlank(bean.getAuditingType().toString())) {
            cnd.and("auditing_type", "=", bean.getAuditingType());
        }
        if (StrUtil.isNotBlank(bean.getCommunity())) {
            cnd.and("community", "=", bean.getCommunity());
        }
        if (bean.getIsDisplay() != null && bean.getIsDisplay()) {
            // 求救首页显示：审核通过/匹配成功/匹配失败/待帮助  或者， 求助首页显示：审核通过并且大于5分钟 审核通过的 匹配成功的 匹配失败的
            // wzy 2023-4-24 下面这句话还是改用sql来进行了，要不然麻烦的很咯
            if(StrUtil.isNotBlank(bean.getSqlString())){
              cnd.and(WxEvent::getShowFlag,"=","1");
            }else {
                String sql = "(( event_type = 'emergency_events' AND ( event_status = 'Y' OR event_status = 'matching' OR event_status = 'match_failed' OR event_status = 'pending_evaluation' ) ) " +
                        "OR ( event_type = 'natural_disaster' AND show_flag is null and ( event_status = 'match_failed' OR ( event_status = 'matching' AND create_time < ( SELECT now( ) - INTERVAL '5 minutes' ) ) ) ) ) ";
                cnd.and(new Static(sql));
            }


        } else {
            if (bean.getEventStatus() != null && Strings.isNotBlank(bean.getEventStatus().toString())) {
                cnd.and("event_status", "=", bean.getEventStatus());
            }
        }
        return cnd;
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public WxEvent preAdd(WxEvent wxEvent) {
        // 根据eventId删除eventSchedule的信息 伪删除
        wxeventscheduleService.updateDelFlagByEventId(wxEvent.getId());
        // 更新最新的事件
        wxEvent.setEventStatus("N");
        wxEvent.setEventCreateTime(new Date());
        wxEvent.setCreateTime(new Date());
        wxEvent.setUpdateTime(new Date());
        dao().update(wxEvent);
        return wxEvent;
    }

    /**
     * 缓存事件列表
     */
    @Override
    public void clearSetCacheList() {
        List<?> list = query();
        RedisUtils.deleteObject(CacheConstants.MINIAPP_EVENT_ALL_LIST_KEY);
        RedisUtils.setCacheList(CacheConstants.MINIAPP_EVENT_ALL_LIST_KEY, list);
        //缓存时间设置7天
        RedisUtils.expire(CacheConstants.MINIAPP_EVENT_ALL_LIST_KEY, Duration.ofDays(7));
    }

    /**
     * 发送模板消息
     */
    @Override
    public void sendMessage(String openId, String eventId) throws Exception{

            WxEvent vo = this.fetch(eventId);

            // wzy 2023-4-23 如果事件发起人也是志愿者，那么不推送给这个志愿者
            // wzy 2023-5-16 因为有些数据是从第三方转过来的openId是空的
            if (StringUtils.isNotBlank(vo.getOpenid())) {
                if (vo.getOpenid().equals(openId))
                   throw new BaseException("志愿者和发起人不能一样");
            } else if (StringUtils.isNotBlank(vo.getEventPhone())) {
                // 根据openId查询数据库中志愿者电话，如果电话相同那么也不推送
                WxVolunteer volunteer = wxvolunteerService.fetch(openId);
                if (volunteer == null){
                    throw new BaseException("无法查看到志愿者信息");
                }
                if (vo.getEventPhone().equals(volunteer.getPhone())){
                    throw new BaseException("志愿者和发起人手机号一样");
                }
            }

            // wzy 2023-4-23 通知的地点修改为街道
            // String address = vo.getEventProvince() + vo.getEventCity();
            String address = vo.getEventStreet();
            if (StringUtils.isBlank(address))
                address = vo.getEventProvince() + vo.getEventCity();  //还是做个兜底如果没有街道还是显示 省市信息

            Date day = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String times = sdf.format(day);

            WechatMiniProgramTemplateMessageUtil.sendTemplateMessage(openId, eventId, times, address);

            // 发送信息之后需要减少志愿者微信推送次数
            // TODO 这里需要判断一下如果是没有发送成功则不减少
            WxVolunteerSMPassCheck bo = new WxVolunteerSMPassCheck(openId, 1, -1);
            wxvolunteerService.addSMPassCheck(bo);

    }

    @Override
    public WxEventStatisticVO getHomePageEventStatistic() {
        Sql sqlCount = Sqls.create("select count(1) from wx_event where ( event_type = 'natural_disaster' or event_type = 'emergency_events') and event_status != 'canceled'");
        this.execute(sqlCount);
        Integer platformTotal = sqlCount.getInt();

        DateTime beginOfDay = DateUtil.beginOfDay(new Date());
        DateTime endOfDay = DateUtil.endOfDay(new Date());
        Sql sqlTodayRe = Sqls.create("select count(1) from wx_event where ( event_type = 'natural_disaster' or event_type = 'emergency_events') and event_status != 'canceled' and create_time >= @beginOfDay and create_time <= @endOfDay");
        dao().execute(sqlTodayRe).setParam("beginOfDay", beginOfDay).setParam("endOfDay", endOfDay);
        Integer todayRelease = sqlTodayRe.getInt();

        Sql sqlTodayFi = Sqls.create("select count(1) from wx_event where ( event_type = 'natural_disaster' or event_type = 'emergency_events') and event_status = 'finished' and create_time >= @beginOfDay and create_time <= @endOfDay");
        dao().execute(sqlTodayFi).setParam("beginOfDay", beginOfDay).setParam("endOfDay", endOfDay);
        Integer todayFinish = sqlTodayFi.getInt();

        WxEventStatisticVO resultVO = new WxEventStatisticVO();
        resultVO.setPlatformTotal(platformTotal);
        resultVO.setTodayRelease(todayRelease);
        resultVO.setTodayFinish(todayFinish);
        return resultVO;
    }

    public Pagination homePageList(WxEvent queryDTO, int pageNo, int pageSize) {
        // 核心展示逻辑
        // 求救首页显示：审核通过/匹配成功/匹配失败/待帮助  或者， 求助首页显示：审核通过并且大于5分钟 审核通过的 匹配成功的 匹配失败的
        String keyQuerySqlStr = "(( event_type = 'emergency_events' AND ( event_status = 'Y' OR event_status = 'matching' OR event_status = 'match_failed' OR event_status = 'pending_evaluation' ) ) " +
                "OR ( event_type = 'natural_disaster' AND ( event_status = 'match_failed' OR ( event_status = 'matching' AND create_time < ( SELECT now() - INTERVAL '5 minutes' ))))) ";
        String orderSqlStr = "ORDER BY create_time DESC";
        if (queryDTO.getLongitude() != null && queryDTO.getLatitude() != null) {
            orderSqlStr = " ORDER BY ABS ( to_number( longitude, '999.99999999' ) - " + queryDTO.getLongitude() + " ) + ABS ( to_number( latitude, '999.99999999' ) -  " + queryDTO.getLatitude() + " ) , create_time DESC";
        }

        List<WxEvent> loginUserEventList = Lists.newArrayList();
        Set<String> loginUserEventIdSet = Sets.newHashSet();
        if (1 == pageNo && StringUtils.isNotBlank(queryDTO.getOpenid())) {
            // 如果是第一页，需要将自己发布的事件需要置顶
            Cnd cnd = Cnd.NEW();
            cnd.and("open_id", "=", queryDTO.getOpenid());
            cnd.and(new Static(keyQuerySqlStr));
            cnd.and(new Static(orderSqlStr));
            loginUserEventList = this.query(cnd);
            loginUserEventIdSet = loginUserEventList.stream().map(WxEvent::getId).collect(Collectors.toSet());
        }
        // 根据查询条件组装SQL
        Cnd cnd = Cnd.NEW();
        if (StringUtils.isNotBlank(queryDTO.getEventType())) {
            cnd.and("event_type", "=", queryDTO.getEventType());
        }
        if (StringUtils.isNotBlank(queryDTO.getEventTitle())) {
            cnd.and("event_title", "like", "%" + queryDTO.getEventTitle() + "%");
        }
        if (StringUtils.isNotBlank(queryDTO.getEventContent())) {
            cnd.and("event_content", "like", "%" + queryDTO.getEventContent() + "%");
        }
        if (StringUtils.isNotBlank(queryDTO.getEventAddress())) {
            cnd.and("event_address", "like", "%" + queryDTO.getEventAddress() + "%");
        }
        if (StringUtils.isNotBlank(queryDTO.getEventIndex())) {
            cnd.and("event_index", "=", queryDTO.getEventIndex());
        }
        if (StringUtils.isNotBlank(queryDTO.getEventProvince())) {
            cnd.and("event_province", "=", queryDTO.getEventProvince());
        }
        if (StringUtils.isNotBlank(queryDTO.getEventCity())) {
            cnd.and("event_city", "=", queryDTO.getEventCity());
        }
        if (StringUtils.isNotBlank(queryDTO.getEventDistrict())) {
            cnd.and("event_district", "=", queryDTO.getEventDistrict());
        }
        if (StringUtils.isNotBlank(queryDTO.getEventDistrict())) {
            cnd.and("event_district", "=", queryDTO.getEventDistrict());
        }
        if (StringUtils.isNotBlank(queryDTO.getEventStreet())) {
            cnd.and("event_street", "=", queryDTO.getEventStreet());
        }

        if (loginUserEventIdSet.size() > 0) {
            StringBuffer sb = new StringBuffer();
            sb.append("(");
            loginUserEventIdSet.forEach(idItem -> {
                sb.append("'").append(idItem).append("',");
            });
            //截掉最后一个,
            sb.delete(sb.length() - 1, sb.length());
            sb.append(")");

            SqlExpressionGroup exp = new SqlExpressionGroup();
            exp.andNotIn("id", sb.toString());
            cnd.and(exp);
        }
        cnd.and(new Static(keyQuerySqlStr));
        cnd.and(new Static(orderSqlStr));

        Pagination wxEventPage = this.listPage(pageNo, pageSize, cnd);
        List<WxEvent> wxEventList = wxEventPage.getList(WxEvent.class);

        List<WxEvent> allEventList = Lists.newArrayList();
        allEventList.addAll(loginUserEventList);
        allEventList.addAll(wxEventList);

        List<WxEventVo> resultList = Lists.newArrayList();
        for (WxEvent wxEvent : allEventList) {
            WxEventVo vo = new WxEventVo();
            BeanUtil.copyProperties(wxEvent, vo);
            // 计算距离
            if (queryDTO.getLongitude() != null && queryDTO.getLatitude() != null) {
                Double distance = DistanceUtils.latitudeLongitudeDistance(vo.getLatitude(), vo.getLongitude(),
                        Double.valueOf(queryDTO.getLatitude()), Double.valueOf(queryDTO.getLongitude()));
                vo.setDistanceForMe(distance);
            }
            if (vo.getOpenid().equals(queryDTO.getOpenid())) {
                vo.setMyEventFlag(true);
            }
            resultList.add(vo);
        }
        Pagination wxEventResultPage = new Pagination();
        wxEventResultPage.setList(resultList);
        // 如果是第一页数据需要进行处理一下
        if (1 == pageNo) {
            wxEventResultPage.setTotalCount(wxEventList.size());
        }
        return wxEventResultPage;
    }

    /**
     * 修改事件
     */
    @Override
    public Boolean updateByBo(WxEvent bo) {

//        if(bo.getCompleteType()=="Y"||bo.getCompleteType()=="true"||bo.getCompleteType()=="N"||bo.getCompleteType()=="no")
//        {
//            insertiWxEventScheduleService(bo);
//        }
        WxEvent update = BeanUtil.toBean(bo, WxEvent.class);
        //validEntityBeforeSave(update);
        // setCacheList();

        if (bo.getEventStatus() != null && bo.getEventType() != null) {
            //pending_evaluation  再次接单 清空志愿者信息
            if ((bo.getEventStatus().equals("Y") && bo.getEventType().equals("natural_disaster")) || (bo.getEventStatus().equals("Y") && bo.getEventType().equals("emergency_events")))//求助
            {
                update.setVolunteerName("");
                update.setVolunteerId("");
                update.setVolunteerSex("");
                update.setVolunteerPhone("");
                update.setVolunteerWhetherHelp("");
                update.setVolunteerYear("");
            }
        }
        // setCacheList();
        /*Cnd cnd = Cnd.NEW();
        cnd.and("id", "=", update.getId());*/

        return updateIgnoreNull(update) > 0;
    }


}
